<?php
/*--------------------------------------------------
| TAR/GZIP/BZIP2/ZIP ARCHIVE CLASSES 2.1
| By Devin Doucette
| Copyright (c) 2005 Devin Doucette
| Email: darksnoopy@shaw.ca
+--------------------------------------------------
| Email bugs/suggestions to darksnoopy@shaw.ca
+--------------------------------------------------
| This script has been created and released under
| the GNU GPL and is free to use and redistribute
| only if this copyright statement is not removed
+--------------------------------------------------*/
include_once(dirname(__FILE__).'/archive.class.php5');
class tar_file extends archive
{
	function tar_file($name)
	{
		$this->archive($name);
		$this->options['type'] = "tar";
	}

	function create_tar()
	{
		$pwd = getcwd();
		chdir($this->options['basedir']);

		foreach ($this->files as $current)
		{
			if ($current['name'] == $this->options['name'])
			continue;
			if (strlen($current['name2']) > 99)
			{
				$path = substr($current['name2'], 0, strpos($current['name2'], "/", strlen($current['name2']) - 100) + 1);
				$current['name2'] = substr($current['name2'], strlen($path));
				if (strlen($path) > 154 || strlen($current['name2']) > 99)
				{
					$this->error[] = "Could not add {$path}{$current['name2']} to archive because the filename is too long.";
					continue;
				}
			}
			$block = pack("a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12", $current['name2'], sprintf("%07o",
			$current['stat'][2]), sprintf("%07o", $current['stat'][4]), sprintf("%07o", $current['stat'][5]),
			sprintf("%011o", $current['type'] == 2 ? 0 : $current['stat'][7]), sprintf("%011o", $current['stat'][9]),
			"        ", $current['type'], $current['type'] == 2 ? @readlink($current['name']) : "", "ustar ", " ",
			"Unknown", "Unknown", "", "", !empty ($path) ? $path : "", "");

			$checksum = 0;
			for ($i = 0; $i < 512; $i++)
			$checksum += ord(substr($block, $i, 1));
			$checksum = pack("a8", sprintf("%07o", $checksum));
			$block = substr_replace($block, $checksum, 148, 8);

			if ($current['type'] == 2 || $current['stat'][7] == 0)
			$this->add_data($block);
			else if ($fp = @fopen($current['name'], "rb"))
			{
				$this->add_data($block);
				while ($temp = fread($fp, 1048576))
				$this->add_data($temp);
				if ($current['stat'][7] % 512 > 0)
				{
					$temp = "";
					for ($i = 0; $i < 512 - $current['stat'][7] % 512; $i++)
					$temp .= "\0";
					$this->add_data($temp);
				}
				fclose($fp);
			}
			else
			$this->error[] = "Could not open file {$current['name']} for reading. It was not added.";
		}

		$this->add_data(pack("a1024", ""));

		chdir($pwd);

		return 1;
	}

	function extract_files($filters, $hook_fct=null, $read_start=array(0, array(), array()))
	{
		global $start_time;
		$errors = array();
		$succes = array();
		$curr_dir = $this->options['basedir'].'/';
		$last_name = '';
		if ($fp = $this->open_archive())
		{
			if($hook_fct!==null)
			{
				while(!feof($fp))
				{
					fread($fp, 4098);
				}
				$file_size = ftell($fp);
				rewind($fp);
			}
			
			if ($this->options['inmemory'] == 1)
			{
				$this->files = array ();
			}
			$last_progres= microtime(true);
			if($read_start[0]>0)
			{
				fseek($fp, intval($read_start[0]));
				$errors = $read_start[1];
				$succes = $read_start[2];
			}
			
			while ($block = fread($fp, 512))
			{
				if($hook_fct!==null)
				{
					$ok = $hook_fct(ftell($fp)-512, $file_size, $last_name, $errors, $succes);
					if(!$ok)
					{
						return false;
					}
				}

				$temp = unpack('a100name/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100symlink/a6magic/a2temp/a32temp/a32temp/a8temp/a8temp/a155prefix/a12temp', $block);
				$file = array (
				'name' => $temp['prefix'] . $temp['name'],
				'stat' => array (
				2 => $temp['mode'],
				4 => octdec($temp['uid']),
				5 => octdec($temp['gid']),
				7 => octdec($temp['size']),
				9 => octdec($temp['mtime']),
				),
				'checksum' => octdec($temp['checksum']),
				'type' => $temp['type'],
				'magic' => $temp['magic'],
				);

				if ($file['checksum'] == 0x00000000)
				{
					break;
				}
				elseif (substr($file['magic'], 0, 5) != 'ustar')
				{
					$errors[] = $file['name'].' : type unknown ['.$file['magic'].']';
					continue;
				}
				$block = substr_replace($block, "        ", 148, 8);
				$checksum = 0;
				for ($i = 0; $i < 512; $i++)
				$checksum += ord(substr($block, $i, 1));
				if ($file['checksum'] != $checksum)
				{
					$errors[] = $file['name'].' : bad checksum';
					continue;
				}

				$filter_ok = false;
				foreach ($filters as $filter)
				{
					if($filter[0]!='')
					{
						if(substr($file['name'], 0, strlen($filter[0]))!=$filter[0])
						{
							continue;
						}
						if($filter[1]!='*')
						{
							if(basename($file['name'])!=$filter[1])
							{
								continue;	
							}

						}
						$file['name'] = substr($file['name'], strlen($filter[0]));
						$filter_ok = true;
						break;
					}
					else
					{
						if($filter[1]!='*')
						{
							if($file['name']==$filter[1])
							{
								$filter_ok = true;
								break;
							}

						}
					}
				}
				if(!$filter_ok)
				{
					if ($file['type'] == 5) continue;
					if($file['stat'][7]>0)
					{
						@fread($fp, $file['stat'][7]);
					}
					if($file['stat'][7] % 512>0)
					{
						@fread($fp, 512 - $file['stat'][7] % 512);
					}
					continue;
				}
				if ($this->options['inmemory'] == 1)
				{
					if($file['stat'][7]>0)
					{
						$file['data'] = fread($fp, $file['stat'][7]);
					}
					if($file['stat'][7] % 512>0)
					{
						fread($fp, 512 - $file['stat'][7] % 512);
					}
					unset ($file['checksum'], $file['magic']);
					$this->files[] = $file;
				}
				elseif ($file['type'] == 5)
				{
					if(!@fwTools::mkdirTree($curr_dir, $file['name']))
					{
						$errors[] = $file['name'].' : Could not create the directory';
					}
				}
				elseif ($this->options['overwrite'] == 0 && file_exists($curr_dir.$file['name']))
				{
					$errors[] = $file['name'].' : already exists';
					continue;
				}
				else
				{
					$last_name = $file['name'];
					if(!@fwTools::mkdirTree($curr_dir, dirname($file['name'])))
					{
						$errors[] = $file['name'].' : Could not create the directory';
						continue;
					}
					elseif ($new = @fopen($curr_dir.$file['name'], "wb"))
					{
						if($file['stat'][7]>0)
						{
							fwrite($new, fread($fp, $file['stat'][7]));
							
						}
						if($file['stat'][7] % 512>0)
						{
							fread($fp, 512 - $file['stat'][7] % 512);
						}
						fclose($new);
						//chmod($file['name'], $file['stat'][2]);
						$succes[] = $curr_dir.$file['name'];
					}
					else
					{
						$errors[] = $file['name'].' : Could not open for writing';
						continue;
					}
				}
				//chown($file['name'], $file['stat'][4]);
				//chgrp($file['name'], $file['stat'][5]);
				//touch($file['name'], $file['stat'][9]);
				unset ($file);
			}
		}
		else
		{
			$errors[] = 'Could not open file '.$this->options['name'];
		}
		return array($errors, $succes);
	}

	function open_archive()
	{
		return @fopen($this->options['name'], "rb");
	}
}
?>